package EP::Rclient;

use EP::Config;
use EP::Common;
use EP::Common::Error qw ( :try );

use R;

sub instance
    {
    my $class = shift;

    # get a reference to the _instance variable in the $class package 
    no strict 'refs';
    my $instance = \${ "$class\::_instance" };

    defined $$instance
        ? $$instance
        : ($$instance = $class->_new_instance(@_));
    }

sub _new_instance
    {
    initR();
    bless { }, $_[0];
    }

sub initR
    {
    warn "[Rclient] initializing R...\n" if DEBUG;

    &R::initR("--silent", "--vanilla");
    &R::suppressOutput(1);
    }

sub evalR
    {
    my $self = shift;
    my $eval = shift;

    # temporary redirect all unwanted stdout to /dev/null
    open TMPOUT, '>&', \*STDOUT or die "Can't dup stdout: $!\n";
    open STDOUT, '>/dev/null' or die "Can't redirect stdout: $!\n";

    my @res;
    warn "[Rclient] calling R:\n$eval\n" if DEBUG;

    try
        {
        @res = &R::eval($eval);
        }
    otherwise
        {
        # return stdout to the original state
        open STDOUT, '>&', \*TMPOUT or die "Can't restore stdout: $!\n";

        throw EP::Common::Error ( -value => RERROR, -err_args => [ &R::getLastOutput() ] );
        };

    # return stdout to the original state
    open STDOUT, '>&', \*TMPOUT or die "Can't restore stdout: $!\n";

    return wantarray ? @res : $res[0];
    }


sub getLastOutput
    {
    my $self = shift;

    return &R::getLastOutput();
    }

sub R
    {
    my $self = shift;
    my $eval = shift;

    return EP::Rclient->instance()->evalR($eval);
    }

1;
